﻿using AiBLSmartEdu.Module.ToDo.API.DTOs;
using AutoMapper;
using Domain.Entities.ToDo;
using FrameworkCore.DI;
using FrameworkCore.Extensions;
using FrameworkCore.Helpers;
using FrameworkCore.Interfaces;
using FrameworkCore.Migrations.Data;
using FrameworkCore.Models;
using FrameworkCore.Repositories;
using Microsoft.EntityFrameworkCore;

namespace AiBLSmartEdu.Module.ToDo.API.Services;

#nullable disable

/// <summary>
/// 待办事项服务
/// </summary>
public class ToDoServices : IScopedDependency
{
    private readonly IRepository<ToDoCategory> _toDoCategoryRepository;
    private readonly IRepository<ToDoItem> _toDoItemRepository;
    private readonly IRepository<ToDoItemCategory> _toDoItemCategoryRepository;
    private readonly IMapper _mapper;
    private readonly ICurrentUserService _currentUserService;

    public ToDoServices(
        IRepository<ToDoCategory> toDoCategoryRepository, 
        IRepository<ToDoItem> toDoItemRepository, 
        IRepository<ToDoItemCategory> toDoItemCategoryRepository, 
        IMapper mapper, 
        ICurrentUserService currentUserService)
    {
        _toDoCategoryRepository = toDoCategoryRepository;
        _toDoItemRepository = toDoItemRepository;
        _toDoItemCategoryRepository = toDoItemCategoryRepository;
        _mapper = mapper;
        _currentUserService = currentUserService;
    }

    /// <summary>
    /// 分页查询
    /// </summary>
    /// <param name="filter">分页输入模型</param>
    /// <returns></returns>
    public async Task<PageResult<ToDoItemOutputModel>> PageAsync(ToDoItemPaginationFilter filter)
    {
        return (await _toDoItemRepository.GetOrderedQueryable(query =>
        {
            return
            query
            .Where(x => x.CustomerId == _currentUserService.CurrentUserId)
            .WhereIf(!filter.Title.IsNullOrWhiteSpace(), x => x.Title.Contains(filter.Title))
            .WhereIf(!filter.Description.IsNullOrWhiteSpace(), x => x.Description.Contains(filter.Description))
            .WhereIf(filter.DueDate.HasValue, x => x.DueDate.Value.Day == filter.DueDate.Value.Day)
            .WhereIf(filter.IsCompleted.HasValue, x => x.IsCompleted == filter.IsCompleted)
            .WhereIf(filter.Priority.HasValue, x => x.Priority == filter.Priority);

        }, filter)
            .ProjectToPaginatedDataAsync<ToDoItem, ToDoItemOutputModel>(
            filter.PageNumber,
            filter.PageSize,
            _mapper.ConfigurationProvider
        )).ToPageList();
    }

    /// <summary>
    /// 获取用户事项类别
    /// </summary>
    /// <returns></returns>
    public async Task<List<CategoryOutputModel>> GetCustomerToDoItemCategoryAsync() 
    {
        var customerToDoItemCategories = await _toDoCategoryRepository
            .Query(x => x.CustomerId == _currentUserService.CurrentUserId)
            .ToListAsync();

        return _mapper.Map<List<CategoryOutputModel>>(customerToDoItemCategories);
    }


    /// <summary>
    /// 创建类别
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    public async Task CreateCategoryAsync(CategoryCreateInputModel input)
    {
        var customerId = _currentUserService.CurrentUserId;

        var exist = await _toDoCategoryRepository
            .Query(x => x.Name == input.Name && x.CustomerId == customerId)
            .AnyAsync();
        if (!exist) 
        {
            var model = _mapper.Map<ToDoCategory>(input);
            model.CustomerId = customerId;
            await _toDoCategoryRepository.InsertAsync(model);
        }
    }

    /// <summary>
    /// 创建待办
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    public async Task CreateToDoItemAsync(ToDoItemCreateInputModel input)
    {
        var customerId = _currentUserService.CurrentUserId;

        var existCategories = await _toDoCategoryRepository
           .Query(x => input.Categories.Contains(x.Id))
           .ToListAsync();
        if (existCategories.Count() != input.Categories.Count)
        {
            // 找到不存在的分类ID
            var existingCategoryIds = existCategories.Select(c => c.Id).ToList();
            var nonExistentCategories = input.Categories.Except(existingCategoryIds);

            var message = $"分类不存在: {string.Join(", ", nonExistentCategories)}";
            ExceptionHelper.ThrowIfFalse(false, message);
        }

        var model = _mapper.Map<ToDoItem>(input);
        model.CustomerId = customerId;
        await _toDoItemRepository.InsertAsync(model);

        foreach (var category in input.Categories) 
        {
            await _toDoItemCategoryRepository.InsertAsync(new ToDoItemCategory { ToDoCategoryId = category, ToDoItemId = model.Id });
        }
    }

    /// <summary>
    /// 修改待办
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    public async Task UpdateToDoItemAsync(ToDoItemUpdateInputModel input)
    {
        var existItem = await _toDoItemRepository.GetByIdAsync(input.Id);
        ExceptionHelper.ThrowIfTrue(existItem == null, "数据不存在");
        ExceptionHelper.ThrowIfTrue(existItem.IsCompleted.Value, "不能对已完成的任务进行修改");
        
        var customerId = _currentUserService.CurrentUserId;

        var existCategories = await _toDoCategoryRepository
           .Query(x => input.Categories.Contains(x.Id))
           .ToListAsync();
        if (existCategories.Count() != input.Categories.Count)
        {
            // 找到不存在的分类ID
            var existingCategoryIds = existCategories.Select(c => c.Id).ToList();
            var nonExistentCategories = input.Categories.Except(existingCategoryIds);

            var message = $"分类不存在: {string.Join(", ", nonExistentCategories)}";
            ExceptionHelper.ThrowIfFalse(false, message);
        }

        await _toDoItemRepository.UpdateAsync(x => x
            .SetProperty(x => x.Priority, input.Priority)
            .SetProperty(x=>x.DueDate,input.DueDate)
            .SetProperty(x=>x.Description,input.Description)
            .SetProperty(x => x.Title, input.Title),
            x => x.Id == input.Id);

        await _toDoItemCategoryRepository.DeleteAsync(x => x.ToDoItemId == input.Id);
        foreach (var category in input.Categories)
        {
            await _toDoItemCategoryRepository.InsertAsync(new ToDoItemCategory { ToDoCategoryId = category, ToDoItemId = input.Id });
        }
    }

    /// <summary>
    /// 修改待办事项等级
    /// </summary>
    /// /// <param name="itemId">待办事项ID</param>
    /// <param name="priorityType">任务等级</param>
    /// <returns></returns>
    public async Task UpdateToDoItemPriorityAsync(long itemId, ToDoPriorityType priorityType)
    {
        var item = await _toDoItemRepository
            .Query(x => x.Id == itemId)
            .FirstAsync();
        ExceptionHelper.ThrowIfTrue(item == null, "任务不存在");
        ExceptionHelper.ThrowIfTrue(item!.IsCompleted!.Value, "任务已完成，修改任务等级失败");

        await _toDoItemRepository.UpdateAsync(
            x => x.SetProperty(x => x.Priority, priorityType),
            x => x.Id == item.Id);
    }

    /// <summary>
    /// 修改待办事项是否完成
    /// </summary>
    /// <param name="itemId">待办事项ID</param>
    /// <param name="isCompleted">是否完成</param>
    /// <returns></returns>
    public async Task UpdateToDoItemCompletedAsync(long itemId, bool isCompleted)
    {
        var item = await _toDoItemRepository
            .Query(x => x.Id == itemId)
            .FirstOrDefaultAsync();
        ExceptionHelper.ThrowIfTrue(item == null, "任务不存在");

        DateTime? completedTime = isCompleted ? DateTime.Now : null;
        item.IsCompleted = isCompleted;
        item.CompletedTime = completedTime;

        await _toDoItemRepository.UpdateAsync(item);
    }

    /// <summary>
    /// 将过期的待办事项标记为过期
    /// </summary>
    /// <returns></returns>
    public async Task MarkExpiredToDoItemsAsync()
    {
        await _toDoItemRepository.UpdateAsync(x => x.SetProperty(x => x.Remark, "任务超时"),x => x.IsCompleted != true && x.DueDate < DateTime.Now);
    }

    /// <summary>
    /// 删除分类
    /// </summary>
    /// <param name="ids">唯一标识，多个使用英文状态下的逗号（,）隔开</param>
    /// <returns></returns>
    public async Task DeleteCategoryAsync(string ids)
    {
        await DeleteEntitiesAsync(ids, _toDoCategoryRepository);
    }

    /// <summary>
    /// 删除待办事项
    /// </summary>
    /// <param name="ids">唯一标识，多个使用英文状态下的逗号（,）隔开</param>
    /// <returns></returns>
    public async Task DeleteItemAsync(string ids)
    {
        await DeleteEntitiesAsync(ids, _toDoItemRepository);
    }

    /// <summary>
    /// 删除关联分类
    /// </summary>
    /// <param name="itemId">事项唯一标识</param>
    /// <param name="categoryId">分类唯一标识</param>
    /// <returns></returns>
    public async Task DeleteItemCategoryAsync(long itemId, long categoryId)
    {
        await _toDoItemCategoryRepository.DeleteAsync(x => x.ToDoItemId == itemId && x.ToDoCategoryId == categoryId);
    }

    /// <summary>
    /// 通用删除实体方法
    /// </summary>
    /// <param name="ids">唯一标识，多个使用英文状态下的逗号（,）隔开</param>
    /// <param name="repository">要操作的仓储</param>
    /// <returns></returns>
    private async Task DeleteEntitiesAsync<T>(string ids, IRepository<T> repository) where T : BaseEntity
    {
        ExceptionHelper.ThrowIfNull(ids, "删除的唯一标识不能为空");

        List<long> idsToDelete = ids
            .Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)  // 分割字符串
            .Select(id =>
            {
                if (long.TryParse(id.Trim(), out long result))
                {
                    return result;
                }
                else
                {
                    throw new ArgumentException("无效的标识");
                }
            }).ToList();

        await repository.DeleteAsync(x => idsToDelete.Contains(x.Id));
    }
}
